#pragma once
#include <iostream>
#include <assert.h>

namespace xy {

	template<class T>
	struct list_node {
		typedef  list_node<T> node;

		list_node(const T val = T()) 
			:_next(nullptr)
			,_prev(nullptr)
			,_val(val)
		{}
		node* _next;
		node* _prev;
		T _val;
	};

	// typedef list_iterator<T, T&, T*> iterator;
	// typedef list_iterator<T, const T&, const T*> const_iterator;
	template<class T, class Ref, class Ptr>
	struct list_iterator {
		typedef list_node<T> node;
		typedef list_iterator<T, Ref, Ptr> self;
		node* _node;

		list_iterator(node* node = node()) 
			:_node(node)
		{
		}

		Ref operator*() {
			return _node->_val;
		}

		self& operator++() {
			_node = _node->_next;
			return *this;
		}

		self operator++(int) {
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		self& operator--() {
			_node = _node->_prev;
			return *this;
		}

		self operator--(int) {
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}

		Ptr operator->() {
			return &(_node->_val);
		}

		bool operator!=(const self& it) const{
			return _node != it._node;
		}

		bool operator==(const self& it) const{
			return _node == it._node;
		}
	};

	template<class T>
	class list {
	public:
		typedef list_node<T> node;

		typedef list_iterator<T, T&, T*> iterator;
		typedef list_iterator<T, const T&, const T*> const_iterator;

		typedef reverse_iterator<iterator, T&, T*> riterator;
		typedef reverse_iterator<const_iterator, const T&, const T*> const_riterator;

		list() {
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		list(list<T>& ls) {
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;

			auto it = ls.begin();
			while (it != ls.end()) {
				push_back(*it);
				++it;
			}
		}

		~list() {
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear() {
			auto it = begin();
			while (it != end()) {
				it = erase(it);
			}
		}
		iterator begin() {
			return _head->_next;
		}

		iterator end() {
			return _head;
		}

		const_iterator begin() const{
			return _head->_next;
		}

		const_iterator end() const{
			return _head;
		}

		riterator rbegin() {
			return end();
		}

		riterator rend() {
			return begin();
		}

		const_riterator rbegin() const {
			return end();
		}

		const_riterator rend() const {
			return begin();
		}

		list<T>& operator=(list<T>& ls) {
			swap(ls);
			return *this;
		}

		void swap(list<T> ls) {
			std::swap(_head, ls._head);
			std::swap(_size, ls._size);
		}

		void push_back(const T val) {
			insert(end(), val);
		}

		void push_front(const T val) {
			insert(begin(), val);
		}

		iterator insert(iterator pos, const T val) {
			node* cur = pos._node;
			node* prev = cur->_prev;
			node* newnode = new node(val);

			prev->_next = newnode;
			newnode->_prev = prev;

			newnode->_next = cur;
			cur->_prev = newnode;

			++_size;
			return newnode;
		}

		size_t size() {
			return _size;
		}

		void pop_back() {
			erase(--end());
		}

		void pop_front() {
			erase(begin());
		}

		iterator erase(iterator pos) {
			node* cur = pos._node;
			node* prev = cur->_prev;
			node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;

			delete[] cur;
			--_size;
			return next;
		}
	private:
		node* _head;
		size_t _size = 0;
	};
}
